_require "basis.smi"
_require "vector-sig.sml"
_require "space.sig"

functor Load(
  S : sig
    structure V : sig
      type 'a vec = {x: 'a, y: 'a, z: 'a}
      val dim : int
      val tabulate : (int -> 'a) -> 'a vec
      val equal : real vec * real vec -> bool
      val zerov : real vec
      val addv : real vec * real vec -> real vec
      val subv : real vec * real vec -> real vec
      val dotvp : real vec * real vec -> real
      val crossvp : real vec * real vec -> real vec
      val addvs : real vec * real -> real vec
      val mulvs : real vec * real -> real vec
      val divvs : real vec * real -> real vec
      val mapv : ('a -> 'b) -> 'a vec -> 'b vec
      val map3v : ('a * 'b * 'c -> 'd) -> 'a vec * 'b vec * 'c vec -> 'd vec
      val foldv : ('a * 'b -> 'b) -> 'a vec -> 'b -> 'b
      val format : {cvt:'a -> string, lp:string, rp:string, sep:string}
                   -> 'a vec -> string
      val explode : 'a vec -> 'a list
      val implode : 'a list -> 'a vec
      type matrix
      val zerom : matrix
      val addm : matrix * matrix -> matrix
      val outvp : real vec * real vec -> matrix
    end
    datatype body = Body of {acc:real V.vec ref, mass:real, phi:real ref,
                             pos:real V.vec ref, vel:real V.vec ref}
    datatype cell = BodyCell of body | Cell of node array
    and node = Empty | Node of {cell:cell, mass:real ref, pos:real V.vec ref}
    datatype space = Space of {rmin:real V.vec, root:node, rsize:real}
    val nsub : int
    val putCell : cell * int * node -> unit
    val getCell : cell * int -> node
    val mkCell : unit -> cell
    val mkBodyNode : body -> node
    val mkCellNode : cell -> node
    val eqBody : body * body -> bool
    val dumpTree : node -> unit
    val prBody : body -> string
    val prNode : node -> string
  end
) =
struct
  structure S =
  struct
    structure V =
    struct
      type 'a vec = 'a S.V.vec
      val dim : int
      val tabulate : (int -> 'a) -> 'a vec
      val equal : real vec * real vec -> bool
      val zerov : real vec
      val addv : real vec * real vec -> real vec
      val subv : real vec * real vec -> real vec
      val dotvp : real vec * real vec -> real
      val crossvp : real vec * real vec -> real vec
      val addvs : real vec * real -> real vec
      val mulvs : real vec * real -> real vec
      val divvs : real vec * real -> real vec
      val mapv : ('a -> 'b) -> 'a vec -> 'b vec
      val map3v : ('a * 'b * 'c -> 'd) -> 'a vec * 'b vec * 'c vec -> 'd vec
      val foldv : ('a * 'b -> 'b) -> 'a vec -> 'b -> 'b
      val format : {cvt:'a -> string, lp:string, rp:string, sep:string}
                   -> 'a vec -> string
      val explode : 'a vec -> 'a list
      val implode : 'a list -> 'a vec
      type matrix = S.V.matrix
      val zerom : matrix
      val addm : matrix * matrix -> matrix
      val outvp : real vec * real vec -> matrix
    end
    datatype body = datatype S.body
    datatype cell = datatype S.cell
    datatype node = datatype S.node
    datatype space = datatype S.space
    val nsub : int
    val putCell : cell * int * node -> unit
    val getCell : cell * int -> node
    val mkCell : unit -> cell
    val mkBodyNode : body -> node
    val mkCellNode : cell -> node
    val eqBody : body * body -> bool
    val dumpTree : node -> unit
    val prBody : body -> string
    val prNode : node -> string
  end
  structure V =
  struct
    type 'a vec = 'a S.V.vec
    val dim : int
    val tabulate : (int -> 'a) -> 'a vec
    val equal : real vec * real vec -> bool
    val zerov : real vec
    val addv : real vec * real vec -> real vec
    val subv : real vec * real vec -> real vec
    val dotvp : real vec * real vec -> real
    val crossvp : real vec * real vec -> real vec
    val addvs : real vec * real -> real vec
    val mulvs : real vec * real -> real vec
    val divvs : real vec * real -> real vec
    val mapv : ('a -> 'b) -> 'a vec -> 'b vec
    val map3v : ('a * 'b * 'c -> 'd) -> 'a vec * 'b vec * 'c vec -> 'd vec
    val foldv : ('a * 'b -> 'b) -> 'a vec -> 'b -> 'b
    val format : {cvt:'a -> string, lp:string, rp:string, sep:string}
                 -> 'a vec -> string
    val explode : 'a vec -> 'a list
    val implode : 'a list -> 'a vec
    type matrix = S.V.matrix
    val zerom : matrix
    val addm : matrix * matrix -> matrix
    val outvp : real vec * real vec -> matrix
  end
  val makeTree : S.body list * real V.vec * real -> S.space
end
